#include "SQLSelectOrderByItem.h"

#include "../../../Exception/IllegalArgumentException.h"
#include "../../visitor/SQLASTVisitor.h"
#include "../../../utils/log.h"

SQLSelectOrderByItem_NullsOrderType SQLSelectOrderByItem_NullsOrderType::NullsFirst = SQLSelectOrderByItem_NullsOrderType(make_string_ptr("NullsFirst"), 1);
SQLSelectOrderByItem_NullsOrderType SQLSelectOrderByItem_NullsOrderType::NullsLast = SQLSelectOrderByItem_NullsOrderType(make_string_ptr("NullsLast"), 2);

SQLSelectOrderByItem_NullsOrderType::SQLSelectOrderByItem_NullsOrderType(string_ptr name, uint64_t index)
{
  this->name = name;
  this->index = index;
}

SQLSelectOrderByItem_NullsOrderType::SQLSelectOrderByItem_NullsOrderType(SQLSelectOrderByItem_NullsOrderType *nullsOrderType)
{

  this->name = nullsOrderType->name;
  this->index = nullsOrderType->index;
}

string_ptr SQLSelectOrderByItem_NullsOrderType::toFormalString()
{
  if (NullsFirst.name == this->name)
  {
    return make_string_ptr("NULLS FIRST");
  }

  if (NullsLast.name == this->name)
  {
    return make_string_ptr("NULLS LAST");
  }

  throw new IllegalArgumentException();
}

SQLSelectOrderByItem::SQLSelectOrderByItem()
{
}

SQLSelectOrderByItem::SQLSelectOrderByItem(SQLExpr_ptr expr)
{
  this->setExpr(expr);
}

SQLSelectOrderByItem::SQLSelectOrderByItem(SQLExpr_ptr expr, SQLOrderingSpecification_ptr type)
{
  this->setExpr(expr);
  this->type = type;
}

SQLExpr_ptr SQLSelectOrderByItem::getExpr()
{
  return this->expr;
}

void SQLSelectOrderByItem::setExpr(SQLExpr_ptr expr)
{
  if (expr != NULL)
  {
    expr->setParent(SharedObject(SQLSelectOrderByItem));
  }
  this->expr = expr;
}

void SQLSelectOrderByItem::setExpr(SQLObject_ptr expr)
{
  if (expr != NULL)
  {
    expr->setParent(SharedObject(SQLSelectOrderByItem));
  }
  this->expr = (std::dynamic_pointer_cast<SQLExpr>(expr)); // expr.get();
}

string_ptr SQLSelectOrderByItem::getCollate()
{
  return collate;
}

void SQLSelectOrderByItem::setCollate(string_ptr collate)
{
  this->collate = collate;
}

SQLOrderingSpecification_ptr SQLSelectOrderByItem::getType()
{
  return this->type;
}

void SQLSelectOrderByItem::setType(SQLOrderingSpecification_ptr type)
{
  this->type = type;
}

SQLSelectOrderByItem_NullsOrderType_ptr SQLSelectOrderByItem::getNullsOrderType()
{
  return this->nullsOrderType;
}

void SQLSelectOrderByItem::setNullsOrderType(SQLSelectOrderByItem_NullsOrderType_ptr nullsOrderType)
{
  this->nullsOrderType = nullsOrderType;
}

void SQLSelectOrderByItem::accept0(SQLASTVisitor_ptr v)
{
  if (v->visit(SharedObject(SQLSelectOrderByItem)))
  {
    if (expr != NULL)
    {
      expr->accept(v);
    }
  }

  v->endVisit(SharedObject(SQLSelectOrderByItem));
}

// int hashCode() {
//     int prime = 31;
//     int result = 1;
//     result = prime * result + ((collate.empty()) ? 0 : collate.hashCode());
//     result = prime * result + ((expr == NULL) ? 0 : expr->hashCode());
//     result = prime * result + ((type == NULL) ? 0 : type->hashCode());
//     return result;
// }

// BOOL_ptr equals(Object obj) {
//     if (this == obj) {
//         return BOOL::TRUE;
//     }
//     if (obj == NULL) {
//         return BOOL::FALSE;
//     }
//     if (getClass() != obj.getClass()) {
//         return BOOL::FALSE;
//     }
//     SQLSelectOrderByItem other = (SQLSelectOrderByItem) obj;
//     if (collate == NULL) {
//         if (other.collate != NULL) {
//             return BOOL::FALSE;
//         }
//     } else if (!collate.equals(other.collate)) {
//         return BOOL::FALSE;
//     }
//     if (expr == NULL) {
//         if (other.expr != NULL) {
//             return BOOL::FALSE;
//         }
//     } else if (!expr.equals(other.expr)) {
//         return BOOL::FALSE;
//     }
//     if (type != other.type) {
//         return BOOL::FALSE;
//     }
//     return BOOL::TRUE;
// }

// BOOL_ptr replace(SQLExpr_ptr expr, SQLExpr_ptr target) {
//     if (this->expr == expr) {
//         if (target instanceof SQLIntegerExpr && parent instanceof SQLOrderBy) {
//             ((SQLOrderBy) parent).getItems().remove(this);
//         }
//         this->setExpr(target);
//         return BOOL::TRUE;
//     }
//     return BOOL::FALSE;
// }

// SQLSelectOrderByItem *SQLSelectOrderByItem::clone()
SQLObject_ptr SQLSelectOrderByItem::clone()
{
  // SQLSelectOrderByItem *x = new SQLSelectOrderByItem();
  SQLObject_ptr clone_tmp = SQLSelectOrderByItem_ptr(new SQLSelectOrderByItem());
  SQLSelectOrderByItem_ptr clone_res = std::dynamic_pointer_cast<SQLSelectOrderByItem>(clone_tmp);
  if (expr != NULL)
  {
    clone_res->setExpr(expr->clone());
  }
  clone_res->collate = collate;
  clone_res->type = type;
  clone_res->nullsOrderType = nullsOrderType;
  // return x;

  return clone_res;
}

SQLSelectItem_ptr SQLSelectOrderByItem::getResolvedSelectItem()
{
  return resolvedSelectItem;
}

void SQLSelectOrderByItem::setResolvedSelectItem(SQLSelectItem_ptr resolvedSelectItem)
{
  this->resolvedSelectItem = resolvedSelectItem;
}

// BOOL_ptr isClusterBy() {
//     if (parent instanceof SQLCreateTableStatement) {
//         std::list<SQLSelectOrderByItem> clusteredBy = ((SQLCreateTableStatement) parent).getClusteredBy();
//         return clusteredBy.indexOf(this) != -1;
//     }

//     if (parent instanceof SQLSelectQueryBlock) {
//         std::list<SQLSelectOrderByItem> clusterBy = ((SQLSelectQueryBlock) parent).getClusterByDirect();
//         return clusterBy != NULL && clusterBy.indexOf(this) != -1;
//     }

//     return BOOL::FALSE;
// }

// BOOL_ptr isSortBy() {
//     if (parent instanceof SQLCreateTableStatement) {
//         std::list<SQLSelectOrderByItem> sortedBy = ((SQLCreateTableStatement) parent).getSortedBy();
//         return sortedBy.indexOf(this) != -1;
//     }

//     if (parent instanceof SQLSelectQueryBlock) {
//         std::list<SQLSelectOrderByItem> sortedBy = ((SQLSelectQueryBlock) parent).getSortByDirect();
//         return sortedBy != NULL && sortedBy.indexOf(this) != -1;
//     }

//     return BOOL::FALSE;
// }

// BOOL_ptr isDistributeBy() {
//     if (parent instanceof SQLSelectQueryBlock) {
//         std::list<SQLSelectOrderByItem> distributeBy = ((SQLSelectQueryBlock) parent).getDistributeBy();
//         return distributeBy.indexOf(this) != -1;
//     }

//     return BOOL::FALSE;
// }
